#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/socket.h> // 用于 socket 相关函数和结构体（如 sockaddr）
#include <arpa/inet.h>  // 用于 inet_pton、inet_ntop 等地址转换函数
#include <strings.h>
#include <string>
#include "Log.hpp"

using namespace LogModule;

const int defaultfd = -1;

class UdpServer
{
public:
    UdpServer(const std::string &ip, uint16_t port)
        : _sockfd(defaultfd),
          _port(port),
          _ip(ip),
          _isrunning(false)
    {
    }

    // 初始化服务器
    void Init()
    {
        // 1.创建socket: domain(通信类型：本地or网络), type(面向数据包or面向字节流：UDP/TCP...),  protocal(协议类型)
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "Creat socket error!";
            exit(1);
        }
        else
        {
            LOG(LogLevel::INFO) << "Creat socket success! sockfd is: " << _sockfd;
        }

        // 2.绑定IP和端口号
        // bind参数1：要绑定的"文件"描述符，参数2：需要绑定的相关信息(IP和端口号)，参数3：sockaddr的长度
        struct sockaddr_in local;

        // 将local的三个字段进行清零和赋值操作：
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;

        // 将local字段中的端口号初始化的时候要转化成为网络序列!!!!
        local.sin_port = htons(_port);

        // 将字符串类型的IP地址传输到网络中进行通信：1.将点分十进制类型转为4字节 2.转为网络序列
        //  inet_addr() 一步到位
        //local.sin_addr.s_addr = inet_addr(_ip.c_str()); //??


        local.sin_addr.s_addr = INADDR_ANY;

        socklen_t addlen;

        int ret = bind(_sockfd, (struct sockaddr *)&local, addlen);

        if (ret < 0)
        {
            LOG(LogLevel::FATAL) << "Bind error!";
            exit(2);
        }
        else
        {
            LOG(LogLevel::INFO) << "Bind success! sockfd is: " << _sockfd;
        }
    }

    // 启动服务器
    void Start()
    {
        _isrunning = true;

        // 死循环式的处理客户端的响应
        while (_isrunning)
        {
            // 1.接受信息
            // sockfd：指定的文件，buf：信息接收到哪里，len：buffer的长度，flags：阻塞or非阻塞，src_addr：消息发送方的相关信息(IP和端口号)，addrlen：src_addr的长度
            // src_addr:输出型参数    addrlen:即为输出型参数又为输入型参数
            // ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

            char buffer[1024];
            // 用来获取远端的socket相关信息(IP和端口号)
            struct sockaddr_in peer;
            socklen_t peer_len;
            ssize_t r = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &peer_len);

            if (r > 0)
            {
                // 在recvfrom的时候给buffer预留了一个位置来存放\0防止乱码
                buffer[r] = '\0';

                std::string msg = "Server get message: ";
                msg += buffer;

                LOG(LogLevel::INFO) << msg;

                // 2.回显信息到客户端
                // sockfd：指定的文件，buf：要发送的信息，len：buffer的长度，flags：阻塞or非阻塞，src_addr：消息接收方的相关信息(IP和端口号)，addrlen：src_addr的长度

                ssize_t s = sendto(_sockfd, msg.c_str(), msg.size(), 0, (const struct sockaddr *)&peer, peer_len);
            }
        }
    }

    ~UdpServer()
    {
    }

private:
    int _sockfd;
    uint16_t _port;
    std::string _ip;
    bool _isrunning;
};